package org.mtmi.ui.controls.curve;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import net.n3.nanoxml.IXMLElement;
import net.n3.nanoxml.IXMLParser;
import net.n3.nanoxml.IXMLReader;
import net.n3.nanoxml.StdXMLReader;
import net.n3.nanoxml.XMLException;
import net.n3.nanoxml.XMLParserFactory;

import org.mtmi.io.ReaderError;
import org.mtmi.io.XMLReader;
import org.mtmi.io.XMLWriter;
import org.mtmi.ui.scenes.SceneManager;

/**
 * Curve value transformer are shared by scenes, this manager in charge to store them.
 * 
 */
public class CurveManager
{
	private static ArrayList<CurveValueTransformer> curves;
	private static ArrayList<ICurveManagerListener> listeners;
	
	private CurveManager() {}
	
	/** @return new curve */
	public static CurveValueTransformer createNewCurve() {
		if( curves==null ) curves = new ArrayList<CurveValueTransformer>();
		CurveValueTransformer c = new CurveValueTransformer();
		curves.add( c );
		return c;
	}
	
	public static CurveValueTransformer[] getCurves() {
		if( curves==null ) 
			return new CurveValueTransformer[0];
		else 
			return curves.toArray( new CurveValueTransformer[curves.size()] );
	}
	
	public static void removeCurve( CurveValueTransformer c ) {
		if( curves.remove( c ) ) {
			notifyCurveRemoved( c );
		}
	}
	
	public static int indexOf( CurveValueTransformer cvt ) {
		if( curves==null ) return -1;
		return curves.indexOf( cvt );
	}
	
	public static CurveValueTransformer getCurve( int index ) {
		if( curves==null ) return null;
		return curves.get( index );
	}
	
	public static void addListener( ICurveManagerListener l ) {
		if( listeners==null ) listeners=new ArrayList<ICurveManagerListener>();
		listeners.add( l );
	}
	
	public static void removeListener( ICurveManagerListener l ) {
		if( listeners==null ) return;
		listeners.remove( l );
	}
	
	private static void notifyCurveRemoved( CurveValueTransformer c ) {
		if( listeners==null ) return ;
		ICurveManagerListener list[] = listeners.toArray( new ICurveManagerListener[listeners.size()] );
		for( ICurveManagerListener l : list ) {
			l.curveRemoved( c );
		}
	}
	
	private static final String FILENAME = "curves.crv";
	static final String E_CURVES   = "curves"; //$NON-NLS-1$
	static final String E_CURVE   = "curve"; //$NON-NLS-1$
	static final String E_POINT   = "point"; //$NON-NLS-1$
	
	static final String A_ID = "id"; //$NON-NLS-1$
	static final String A_X = "x"; //$NON-NLS-1$
	static final String A_Y = "y"; //$NON-NLS-1$
	
	public static void writeCurves()
	{
		String dir = SceneManager.getDefault().getSceneDirectory();
		if( dir==null ) return ; //cannot save.
		
		try {
			
			String fullname = dir+File.separator+FILENAME;
			FileOutputStream fos = new FileOutputStream( fullname );
			XMLWriter xp = new XMLWriter( fos );
			
			xp.startElement( E_CURVES );
			
			if( curves!=null ) {
				for( int i=0; i<curves.size(); i++ ) {
					xp.startElement( E_CURVE );
					xp.addAttr( A_ID, i );
					CurveValueTransformer c = curves.get( i );
					for( FPoint p : c.getPoints() ) {
						xp.addElement( E_POINT, A_X, p.x(), A_Y, p.y() );
					}
					xp.endElement( E_CURVE );
				}
			}
			xp.endElement( E_CURVES );

		} catch( IOException x ) {
			x.printStackTrace(); //TODO a log file ???
		}
	}
	
	public static void readCurve()
	{
		String sdir = SceneManager.getDefault().getSceneDirectory();
		if( sdir==null ) return ; //cannot save.

		curves = new ArrayList<CurveValueTransformer>();
		
		try {
			if( sdir==null ) {
				throw new ReaderError("No scene directory defined: cannot load curves");
			}

			File fdir = new File( sdir );
			if( !fdir.exists() || !fdir.isDirectory() ) {
				throw new ReaderError("Scene directory does not exists or is not a directory: '"+sdir+"'");
			}

			File file = new File( sdir+File.separator+FILENAME );
			if( !file.exists() || !file.isFile() ) {
				return ; //not an error, no curve defined yet
			}

			FileInputStream fis = null;
			try {

				XMLReader xr = new XMLReader();

				IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
				fis = new FileInputStream( file );
				IXMLReader reader = new StdXMLReader( fis );

				parser.setReader(reader);
				IXMLElement e_curves = (IXMLElement) parser.parse();

				if( !E_CURVES.equals( e_curves.getName() ) ) {
					throw new ReaderError("Curve file is not valid."); //$NON-NLS-1$
				}

				//create curves, keep id's in map
				for( Object n : e_curves.getChildren() ) {
					if( n instanceof IXMLElement ) {
						IXMLElement e = (IXMLElement)n;
						if( E_CURVE.equals( e.getName() ) ) {
							int id = xr.getAttrInt( e, A_ID );
							ArrayList<FPoint> points = new ArrayList<FPoint>();
							for( Object nn : e.getChildren() ) {
								if( nn instanceof IXMLElement ) {
									IXMLElement ee = (IXMLElement)nn;
									if( E_POINT.equals( ee.getName() ) ) {
										float x = xr.getAttrFloat( ee, A_X );
										float y = xr.getAttrFloat( ee, A_Y );
										points.add( new FPoint( x, y ) );
									}
								}
							}
							
							curves.add( new CurveValueTransformer(points) );
						}
					}
				}
			}
			finally {
				if( fis!=null ) {
					try {
						fis.close();
					} catch( IOException x ) {
						x.printStackTrace();
					}
				}
			}

		} catch( IOException x ) {
			 x.printStackTrace();
		} catch( IllegalAccessException x ) {
			 x.printStackTrace();
		} catch( InstantiationException x ) {
			 x.printStackTrace();
		} catch( ClassNotFoundException x ) {
			 x.printStackTrace();
		} catch( XMLException x ) {
			 x.printStackTrace();
		} catch( ReaderError x ) {
		   x.printStackTrace();
		}

	}

}
